home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / util / text / words3.lha / Words / SpellIT / source / main.c next >
C/C++ Source or Header  |  1995-08-31  |  45KB  |  1,582 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  SpellIT API client, ©1995 Dietmar Eilert. Dice:
  4.  
  5.  dcc main.c -// -proto -mi -r -2.0 -l localess.lib -l reqtoolss.lib -o ram:SpellIT
  6.  
  7.  Note: Compiling this code requires reqtools includes & reqtools linker
  8.        libraries. The ReqTools library is © Nico François.
  9.  
  10.  The following code adds spell checking capabilities to GoldED. It is  based  on
  11.  the  ISpell International package. You need new the ISpell 3.1 from AmiNet, not
  12.  the old ISpell 3.3LJR distribution. ISpell has to be installed properly  before
  13.  you can use this API client. This example uses synchronous ARexx communication:
  14.  Requests are PutMsg()'ed to GoldED's port, followed by a WaitPort() to get  the
  15.  editor's  response.  This works fine since we need no ARexx communication after
  16.  the API link has been established.  If  there  were  ARexx  communication  with
  17.  GoldED  AFTER  the  link  has  been  established  (i.e.  after sending the 'API
  18.  PORT=...'  command  to  register  with  GoldED),  we  would  have  to  use   an
  19.  asynchronous  design  beeing  capable  of answering incoming API messages while
  20.  waiting for completion of ARexx requests sent to GoldED.
  21.  
  22.   -------------------------------------------------------------------------------
  23. */
  24.  
  25. /// "includes"
  26.  
  27. #define Prototype extern
  28.  
  29. #include <exec/exec.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <dos/dos.h>
  34. #include <dos/dostags.h>
  35. #include <dos/rdargs.h>
  36. #include <intuition/intuition.h>
  37. #include <utility/tagitem.h>
  38. #include <libraries/gadtools.h>
  39. #include <libraries/reqtools.h>
  40. #include <libraries/locale.h>
  41. #include <workbench/startup.h>
  42. #include <rexx/errors.h>
  43. #include <rexx/rxslib.h>
  44. #include <clib/exec_protos.h>
  45. #include <clib/dos_protos.h>
  46. #include <clib/graphics_protos.h>
  47. #include <clib/intuition_protos.h>
  48. #include <clib/diskfont_protos.h>
  49. #include <clib/rexxsyslib_protos.h>
  50. #include <clib/gadtools_protos.h>
  51. #include <clib/reqtools_protos.h>
  52. #include <clib/locale_protos.h>
  53. #include <clib/alib_protos.h>
  54. #include <devices/audio.h>
  55.  
  56. #include "golded:api/include/golded.h"
  57. #include "strings.c"
  58.  
  59. #define EDIT_MAXWIDTH   999                          // maximum line width of editor
  60. #define USERVAR_ONLINE  18                           // user var ID
  61. #define USERVAR_ASK     19                           // user var ID
  62.  
  63. // private API definitions
  64.  
  65. struct SpellConfig {
  66.  
  67.     struct MsgPort *RexxPort;                        // our message port
  68.     UWORD           Volume;                          // beep volume
  69.     BOOL            Ask;                             // show suggestions ?
  70.     BOOL            OnlineCheck;                     // check while typing ?
  71.     char          **AppStrings;                      // localized strings
  72.     UWORD           Count;                           // new word counter
  73.     BOOL            TeX;                             // ignore word starting with '\' ?
  74.     BOOL            Resident;                        // keep ISpell resident
  75.     UWORD           Column;                          // cursor column
  76.     ULONG           Line;                            // cursor line
  77.     UBYTE          *Buffer;                          // current line: data
  78.     UWORD           Len;                             // current line: size
  79. };
  80.  
  81. Prototype BOOL   Exists(UBYTE *);
  82. Prototype void   main(int, char **);
  83. Prototype int    wbmain(struct WBStartup *);
  84. Prototype BOOL   InitISpell(UBYTE *, UBYTE *);
  85. Prototype void   HandleAPI(char *, struct SpellConfig *);
  86. Prototype ULONG *SendRexxCommand(char *, char *, struct MsgPort *, char *);
  87. Prototype void   CheckOnlineWord(struct APIMessage *, struct SpellConfig *);
  88. Prototype void   Beep(UWORD);
  89. Prototype UWORD  ComputeX(struct TextFont *, UWORD);
  90. Prototype UWORD  ComputeY(struct TextFont *, UWORD);
  91. Prototype char  *ShowSpell(char *, struct List *, char *);
  92. Prototype struct Node *SearchNode(struct List *, UWORD);
  93. Prototype void   Dispatch(struct APIMessage *, struct SpellConfig *);
  94. Prototype LONG   CommandSpell(ULONG *, struct APIMessage *, struct SpellConfig *);
  95. Prototype BOOL   EvaluateBool(BOOL *, UWORD, ULONG *);
  96. Prototype UWORD  Information(struct APIMessage *, char *, char *);
  97. Prototype BOOL   AlertInfo(char *);
  98. Prototype LONG   FindNextError(struct APIMessage *, struct SpellConfig *);
  99. Prototype char  *CheckThisWord(struct APIMessage *, struct SpellConfig *, char *, UWORD, BOOL, UWORD);
  100. Prototype void   CheckCurrentWord(struct APIMessage *, struct SpellConfig *, BOOL, UWORD);
  101. Prototype LONG   AddCurrentWord(struct APIMessage *, struct SpellConfig *);
  102. Prototype void   FlushUserDictionary(struct APIMessage *, struct SpellConfig *);
  103. Prototype void   RememberCursorPosition(struct APIMessage *, struct SpellConfig *);
  104. Prototype BOOL   DoNextWord(struct APIMessage *, struct SpellConfig *, BOOL);
  105. Prototype BOOL   IsASpace(UBYTE, BOOL);
  106. Prototype BOOL   DoRightSmart(struct APIMessage *, struct SpellConfig *);
  107. Prototype void   DoRight(struct APIMessage *, struct SpellConfig *);
  108. Prototype void   DoDown (struct APIMessage *, struct SpellConfig *);
  109. Prototype void   Replace(struct APIMessage *, struct SpellConfig *, UWORD, UWORD, char *);
  110.  
  111. struct Library *ReqToolsBase;
  112. struct Library *LocaleBase;
  113.  
  114. ///
  115. /// "init"
  116.  
  117. /* -------------------------------- InitISpell ---------------------------------
  118.  
  119.  Prepare ISpell. Return TRUE if successful.
  120.  
  121. */
  122.  
  123. BOOL
  124. InitISpell(language, args)
  125.  
  126. UBYTE *language, *args;
  127. {
  128.     if (FindPort("IRexxSpell"))
  129.  
  130.         return(TRUE);
  131.  
  132.     else {
  133.  
  134.         static UBYTE command[255], hashfile[255], personal[255], home[255];
  135.  
  136.         BPTR handle;
  137.  
  138.         // $HOME required by ISpell 3.1.18
  139.  
  140.         if (GetVar("HOME", home, sizeof(home), GVF_GLOBAL_ONLY) == -1)
  141.             SetVar("HOME", "sys:", -1, GVF_GLOBAL_ONLY);
  142.  
  143.         if (language == NULL)
  144.             language = "english";
  145.  
  146.         sprintf(hashfile, "ispell:lib/%s.hash", language, language);
  147.  
  148.         sprintf(personal, "/ispell/lib/.ispell_%s", language);
  149.  
  150.         if (Exists(hashfile)) {
  151.  
  152.             if (handle = Open("NIL:", MODE_NEWFILE)) {
  153.  
  154.                 struct TagItem tags[] = {
  155.  
  156.                     SYS_Input,    handle,
  157.                     SYS_Output,   NULL,
  158.                     SYS_Asynch,   TRUE,
  159.                     NP_StackSize, 25600,
  160.                     TAG_DONE
  161.                 };
  162.  
  163.                 // run ISpell in host mode
  164.  
  165.                 if (args)
  166.                     sprintf(command, "ispell -d%s -p%s -r %s", hashfile, personal, args);
  167.                 else
  168.                     sprintf(command, "ispell -d%s -p%s -r", hashfile, personal);
  169.  
  170.                 if (SystemTagList(command, tags) != -1) {
  171.  
  172.                     UWORD try;
  173.  
  174.                     for (try = 100; try--; Delay(10)) {
  175.  
  176.                         Forbid();
  177.  
  178.                         if (FindPort("IRexxSpell"))
  179.                             break;
  180.  
  181.                         Permit();
  182.                     }
  183.  
  184.                     if (try)
  185.                         return(TRUE);
  186.                 }
  187.                 else
  188.                     Close(handle);
  189.  
  190.                 AlertInfo("ISpell not available");
  191.             }
  192.         }
  193.         else {
  194.  
  195.             strins(hashfile, "dictionary missing: ");
  196.  
  197.             AlertInfo(hashfile);
  198.         }
  199.     }
  200.  
  201.     return(FALSE);
  202. }
  203.  
  204. ///
  205. /// "main"
  206.  
  207. int
  208. wbmain(struct WBStartup *wbs)
  209. {
  210.     main(0, NULL);
  211. }
  212.  
  213. void
  214. main(int argc, char **argv)
  215. {
  216.     static UBYTE version[] = "$VER: SpellIT 2.0 (" __COMMODORE_DATE__ ")";
  217.  
  218.     static UBYTE *appStrings[] = {
  219.  
  220.         NOMOREERRORS_STR,
  221.         ATTEMPTTOREGISTERFAILED_STR,
  222.         TOBEUSEDASCLIENT_STR,
  223.         WORDSADDEDSAVECHANGES_STR,
  224.         YESNO_STR,
  225.         ABOUT_STR,
  226.         NOWORDUNDERCURSOR_STR,
  227.         REQTOOLSLIBRARYMISSING_STR,
  228.         NULL
  229.     };
  230.  
  231.     struct Catalog *catalog;
  232.  
  233.     if (LocaleBase = OpenLibrary("locale.library", 0)) {
  234.  
  235.         struct TagItem tags[] = { OC_BuiltInLanguage, "english", TAG_DONE };
  236.  
  237.         ULONG id;
  238.  
  239.         if (catalog = OpenCatalogA(NULL, "spellIT.catalog", tags))
  240.             for (id = 0; appStrings[id]; id++)
  241.                 appStrings[id] = GetCatalogStr(catalog, id, appStrings[id]);
  242.     }
  243.  
  244.     if (ReqToolsBase = OpenLibrary("reqtools.library", 0)) {
  245.  
  246.         ULONG argArray[] = { 0, 0, 0, 0 };
  247.  
  248.         struct RDArgs *rdArgs;
  249.  
  250.         if (rdArgs = ReadArgs("RESIDENT/S,H=HOST/K/A,LANGUAGE/K,ARGS/K", argArray, NULL)) {
  251.  
  252.             struct SpellConfig spellConfig = {
  253.  
  254.                 NULL,                                // no reply port set up so far
  255.                 32                                   // beep volume
  256.                 FALSE,                               // don't show suggestions
  257.                 FALSE,                               // no online check
  258.                 appStrings,                          // localized strings
  259.                 0,                                   // counter: no words added so far
  260.                 FALSE,                               // don't ignore \TeX commands
  261.                 argArray[0]                          // keep ISpell resident
  262.             };
  263.  
  264.             if (InitISpell((UBYTE *)argArray[2], (UBYTE *)argArray[3]))
  265.                 HandleAPI((UBYTE *)argArray[1], &spellConfig);
  266.  
  267.             FreeArgs(rdArgs);
  268.         }
  269.         else
  270.             Information(NULL, appStrings[TOBEUSEDASCLIENT], NULL);
  271.  
  272.         CloseLibrary(ReqToolsBase);
  273.     }
  274.     else
  275.         AlertInfo(appStrings[REQTOOLSLIBRARYMISSING]);
  276.  
  277.     if (LocaleBase) {
  278.  
  279.         CloseCatalog(catalog);
  280.         CloseLibrary(LocaleBase);
  281.     }
  282.  
  283.     exit(0);
  284. }
  285.  
  286. ///
  287. /// "api management"
  288.  
  289. /* --------------------------------- HandleAPI ---------------------------------
  290.  
  291.  Register with GoldED & handle incoming API messages.
  292.  
  293. */
  294.  
  295. void
  296. HandleAPI(host, spellConfig)
  297.  
  298. char  *host;
  299. struct SpellConfig *spellConfig;
  300. {
  301.     struct MsgPort *apiPort;
  302.  
  303.     if (apiPort = CreateMsgPort()) {
  304.  
  305.         if (spellConfig->RexxPort = CreateMsgPort()) {
  306.  
  307.             char  command[255];
  308.             ULONG *result;
  309.  
  310.             sprintf(command, "API PORT=%ld CLASS=%ld", apiPort, API_CLASS_ROOT | API_CLASS_KEY | API_CLASS_REXX);
  311.  
  312.             if (result = SendRexxCommand(host, command, spellConfig->RexxPort, NULL)) {
  313.  
  314.                 if (*result == RC_OK) {
  315.  
  316.                     BOOL active = TRUE;
  317.  
  318.                     do {
  319.  
  320.                         struct APIMessage *apiMsg, *nextMsg;
  321.  
  322.                         while (!(apiMsg = (struct APIMessage *)GetMsg(apiPort)))
  323.                             WaitPort(apiPort);
  324.  
  325.                         do {
  326.  
  327.                             for (nextMsg = apiMsg; nextMsg; nextMsg = nextMsg->api_Next) {
  328.  
  329.                                 if (nextMsg->api_State == API_STATE_NOTIFY) {
  330.  
  331.                                     spellConfig->OnlineCheck = (nextMsg->api_Global->F_User)[USERVAR_ONLINE];
  332.                                     spellConfig->Ask         = (nextMsg->api_Global->F_User)[USERVAR_ASK];
  333.  
  334.                                     switch (nextMsg->api_Class) {
  335.  
  336.                                         case API_CLASS_REXX:
  337.  
  338.                                             switch (nextMsg->api_Action) {
  339.  
  340.                                                 case API_ACTION_COMMAND:
  341.  
  342.                                                     Dispatch(nextMsg, spellConfig);
  343.                                                     break;
  344.  
  345.                                                 default:
  346.  
  347.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  348.                                             }
  349.                                             break;
  350.  
  351.                                         case API_CLASS_ROOT:
  352.  
  353.                                             switch (nextMsg->api_Action) {
  354.  
  355.                                                 case API_ACTION_DIE:
  356.  
  357.                                                     FlushUserDictionary(nextMsg, spellConfig);
  358.                                                     active = FALSE;
  359.  
  360.                                                     break;
  361.  
  362.                                                 case API_ACTION_INTRODUCE:
  363.  
  364.                                                     static struct TagItem tags[] = {
  365.  
  366.                                                         API_Client_Name,      "SpellIT",
  367.                                                         API_Client_Copyright, "SpellIT ©1995 Dietmar Eilert",
  368.                                                         API_Client_Purpose,
  369.  
  370.                                                             "SpellIT is a spell checker, adding online spell   \n"
  371.                                                             "checking capabilities to GED. Default bindings    \n"
  372.                                                             "if using the WORDS keymap:                        \n"
  373.                                                             "                                                  \n"
  374.                                                             "      F6 ............ online spell checking ON    \n"
  375.                                                             "SHIFT-F6 ............ online spell checking OFF   \n"
  376.                                                             "      F7 ............ move cursor to next error   \n"
  377.                                                             "      F8 ............ check word under cursor     \n"
  378.                                                             "      F9 ............ learn word under cursor     \n"
  379.                                                             "      F10 ........... normal error beep           \n"
  380.                                                             "SHIFT-F10 ........... low beep                    \n",
  381.  
  382.                                                         API_Client_Template,  "SPELL ONLINE/K,ABOUT/S,ASK/K,NEXT/S,SUGGEST/S,VOLUME/N,ADD/S,CURRENT/S,TEX/K",
  383.                                                         TAG_DONE
  384.                                                     };
  385.  
  386.                                                     nextMsg->api_Data = tags;
  387.                                                     break;
  388.  
  389.                                                 default:
  390.  
  391.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  392.                                             }
  393.  
  394.                                             break;
  395.  
  396.                                         case API_CLASS_KEY:
  397.  
  398.                                             switch (nextMsg->api_Action) {
  399.  
  400.                                                 case API_ACTION_VANILLAKEY:
  401.  
  402.                                                     if (spellConfig->OnlineCheck) {
  403.  
  404.                                                         // checks are performed after white space characters:
  405.  
  406.                                                         if (IsASpace((UBYTE)nextMsg->api_Data, FALSE))
  407.                                                             CheckOnlineWord(nextMsg, spellConfig);
  408.                                                     }
  409.                                                     break;
  410.  
  411.                                                 default:
  412.  
  413.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  414.                                             }
  415.                                             break;
  416.  
  417.                                         default:
  418.  
  419.                                             nextMsg->api_Error = API_ERROR_UNKNOWN;
  420.                                     }
  421.                                 }
  422.                             }
  423.  
  424.                             ReplyMsg((struct Message *)apiMsg);
  425.  
  426.                         } while (apiMsg = (struct APIMessage *)GetMsg(apiPort));
  427.  
  428.                     } while (active);
  429.                 }
  430.             }
  431.             else
  432.                 AlertInfo(spellConfig->AppStrings[ATTEMPTTOREGISTERFAILED]);
  433.  
  434.             if (!spellConfig->Resident)
  435.                 SendRexxCommand("IRexxSpell", "EXIT", spellConfig->RexxPort, NULL);
  436.  
  437.             DeleteMsgPort(spellConfig->RexxPort);
  438.         }
  439.  
  440.         DeleteMsgPort(apiPort);
  441.     }
  442. }
  443.  
  444.  
  445. ///
  446. /// "arexx class"
  447.  
  448. /* --------------------------------- Dispatch ----------------------------------
  449.  
  450.  Dispatch incoming command: examine command string (command part is uppercase
  451.  already), look for handler function related to command, parse arguments (if 
  452.  command supports arguments), call handler.
  453.  
  454. */
  455.  
  456. void
  457. Dispatch(apiMsg, spellConfig)
  458.  
  459. struct APIMessage  *apiMsg;
  460. struct SpellConfig *spellConfig;
  461. {
  462.     struct RDArgs *rdArgs, *args;
  463.  
  464.     if (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) {
  465.  
  466.         static char buffer[1024];
  467.  
  468.         // table of supported commands, associated handlers & template strings
  469.  
  470.         static struct parser { char *command; LONG (*handler)(ULONG *, struct APIMessage *, struct SpellConfig *); char *template; } parser[] = {
  471.  
  472.             "SPELL",  (APTR)CommandSpell,  "ONLINE/K,ABOUT/S,ASK/K,NEXT/S,SUGGEST/S,VOLUME/N,ADD/S,CURRENT/S,TEX/K",
  473.              NULL
  474.         };
  475.  
  476.         ULONG n, argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  477.  
  478.         struct APIRexxNotify *notify = (struct APIRexxNotify *)apiMsg->api_Data;
  479.  
  480.         // make LF-terminated copy of command string (required by dos/readArgs):
  481.  
  482.         strcpy(buffer, notify->arn_Command);
  483.         strcat(buffer, "\12");
  484.  
  485.         for (n = 0; parser[n].command; ++n) {
  486.  
  487.             if (!memcmp(buffer, parser[n].command, strlen(parser[n].command))) {
  488.  
  489.                 char *arguments = buffer + strlen(parser[n].command);
  490.  
  491.                 rdArgs->RDA_Source.CS_Buffer = arguments;
  492.                 rdArgs->RDA_Source.CS_Length = strlen(arguments);
  493.                 rdArgs->RDA_Source.CS_CurChr = 0;
  494.                 rdArgs->RDA_DAList           = NULL;
  495.                 rdArgs->RDA_Buffer           = NULL;
  496.  
  497.                 if (parser[n].template) {
  498.  
  499.                     if (args = ReadArgs(parser[n].template, argArray, rdArgs)) {
  500.  
  501.                         notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, spellConfig);
  502.  
  503.                         FreeArgs(args);
  504.                     }
  505.                     else {
  506.  
  507.                         static char errorText[81];
  508.  
  509.                         notify->arn_RC           = RC_WARN;
  510.                         notify->arn_CommandError = errorText;
  511.  
  512.                         Fault(IoErr(), "IoErr()", errorText, 80);
  513.                     }
  514.                 }
  515.                 else
  516.                     notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, spellConfig);
  517.             }
  518.         }
  519.  
  520.         FreeDosObject(DOS_RDARGS, rdArgs);
  521.     }
  522. }
  523.  
  524. /* -------------------------------- CommandSpell -------------------------------
  525.  
  526.  ISpell interface
  527.  
  528.  template: ONLINE/K,ABOUT/S,ASK/K,NEXT/S,SUGGEST/S,VOLUME/N,ADD/S,CURRENT/S,TEX/K
  529.  
  530. */
  531.  
  532. LONG
  533. CommandSpell(argArray, apiMsg, spellConfig)
  534.  
  535. ULONG  *argArray;
  536. struct APIMessage  *apiMsg;
  537. struct SpellConfig *spellConfig;
  538. {
  539.     apiMsg->api_State = API_STATE_CONSUMED;
  540.  
  541.     LONG error = RC_OK;
  542.  
  543.     RememberCursorPosition(apiMsg, spellConfig);
  544.  
  545.     if (argArray[0])                                 // ONLINE/K
  546.         apiMsg->api_Global->F_User[USERVAR_ONLINE] = EvaluateBool(&spellConfig->OnlineCheck, 0, argArray);
  547.  
  548.     if (argArray[2])                                 // ASK/K
  549.         apiMsg->api_Global->F_User[USERVAR_ASK] = EvaluateBool(&spellConfig->Ask, 2, argArray);
  550.  
  551.     EvaluateBool(&spellConfig->TeX, 8, argArray);    // TEX/K
  552.  
  553.     if (argArray[5])                                 // VOLUME/N
  554.         spellConfig->Volume = *(ULONG *)argArray[5];
  555.  
  556.     if (argArray[1])                                 // ABOUT/S
  557.         Information(apiMsg, spellConfig->AppStrings[ABOUT], NULL);
  558.  
  559.     if (argArray[6])                                 // ADD/S
  560.          error |= AddCurrentWord(apiMsg, spellConfig);
  561.  
  562.     if (argArray[4])                                 // SUGGEST/S
  563.         CheckCurrentWord(apiMsg, spellConfig, TRUE, FALSE);
  564.  
  565.     if (argArray[7])                                 // CURRENT/S
  566.         CheckCurrentWord(apiMsg, spellConfig, spellConfig->Ask, spellConfig->Volume);
  567.  
  568.     if (argArray[3])                                 // NEXT/S
  569.          error |= FindNextError(apiMsg, spellConfig);
  570.  
  571.     return(error);
  572. }
  573.  
  574. ///
  575. /// "key class"
  576.  
  577. /* -------------------------- RememberCursorPosition ---------------------------
  578.  
  579.  Remember current cursor position
  580.  
  581. */
  582.  
  583. void
  584. RememberCursorPosition(apiMsg, spellConfig)
  585.  
  586. struct APIMessage  *apiMsg;
  587. struct SpellConfig *spellConfig;
  588. {
  589.     struct EditConfig *config = apiMsg->api_Config;
  590.  
  591.     spellConfig->Column = config->Column;
  592.     spellConfig->Line   = config->Line;
  593.     spellConfig->Buffer = config->CurrentBuffer;
  594.     spellConfig->Len    = config->CurrentLen;
  595. }
  596.  
  597.  
  598. /* ---------------------------- CheckOnlineWord ---------------------------------
  599.  
  600.  Check word. This function is called BEFORE  GoldED  actually  inserts  a  white
  601.  space  character  (space, colon, ...) at the current cursor position. We assume
  602.  the current position to  be  a  white  space  character  to  guarantee  correct
  603.  behavior if the user inserts a character into a word. If ISpell complains about
  604.  a word we will either issue a beep (ask = FALSE) or additionally display a list
  605.  of suggestions (<ask> = TRUE).
  606.  
  607.  Excerpt taken from man/ispell.1: If the word is  not  in  the  dictionary,  but
  608.  there  are  near  misses,  then the result line contains an '&', a space, and a
  609.  list of the near misses separated by spaces.
  610.  
  611. */
  612.  
  613. void
  614. CheckOnlineWord(apiMsg, spellConfig)
  615.  
  616. struct APIMessage  *apiMsg;
  617. struct SpellConfig *spellConfig;
  618. {
  619.     struct EditConfig *config = apiMsg->api_Config;
  620.  
  621.     UWORD   column;
  622.     UBYTE  *next;
  623.  
  624.     RememberCursorPosition(apiMsg, spellConfig);
  625.  
  626.     column = spellConfig->Column;
  627.     next   = spellConfig->Buffer + column;
  628.  
  629.     // cursor placed directly after word ?
  630.  
  631.     if (column && !IsASpace(*(next - 1), FALSE)) {
  632.  
  633.         UBYTE *replacement;
  634.         UWORD  wordLen;
  635.  
  636.         // find beginning of word
  637.  
  638.         for (wordLen = 0; column && !IsASpace(*(next - 1), FALSE); --column, --next)
  639.             ++wordLen;
  640.  
  641.         if (replacement = CheckThisWord(apiMsg, spellConfig, next, wordLen, spellConfig->Ask, spellConfig->Volume))
  642.             if (replacement != (UBYTE *)TRUE)
  643.                 Replace(apiMsg, spellConfig, column, wordLen, replacement);
  644.     }
  645. }
  646.  
  647. ///
  648. /// "ISpell"
  649.  
  650. /* ---------------------------- FlushUserDictionary ----------------------------
  651.  
  652.  Aks wether to flush user dictionary to disk
  653.  
  654. */
  655.  
  656. void
  657. FlushUserDictionary(apiMsg, spellConfig)
  658.  
  659. struct APIMessage  *apiMsg;
  660. struct SpellConfig *spellConfig;
  661. {
  662.     if (spellConfig->Count) {
  663.  
  664.         char buffer[80];
  665.  
  666.         sprintf(buffer, spellConfig->AppStrings[WORDSADDEDSAVECHANGES], spellConfig->Count);
  667.  
  668.         if (Information(apiMsg, buffer, spellConfig->AppStrings[YESNO]))
  669.             SendRexxCommand("IRexxSpell", "ADD A", spellConfig->RexxPort, NULL);
  670.     }
  671. }
  672.  
  673. /* ----------------------------- CheckCurrentWord ------------------------------
  674.  
  675.  Check word. If ISpell complains about a word we will either issue a beep (ask =
  676.  FALSE) or additionally display a list of suggestions (<ask> = TRUE).
  677.  
  678. */
  679.  
  680. void
  681. CheckCurrentWord(apiMsg, spellConfig, ask, volume)
  682.  
  683. struct APIMessage  *apiMsg;
  684. struct SpellConfig *spellConfig;
  685. BOOL   ask;
  686. UWORD  volume;
  687. {
  688.     struct EditConfig *config = apiMsg->api_Config;
  689.  
  690.     UWORD  column, wordLen;
  691.     UBYTE *buffer, *replacement;
  692.  
  693.     wordLen = 0;
  694.  
  695.     // find beginning of word
  696.  
  697.     for (column = spellConfig->Column, buffer = spellConfig->Buffer + column; column && IsASpace(*buffer, FALSE); --column)
  698.         --buffer;
  699.  
  700.     while (column && !IsASpace(*(buffer - 1), FALSE)) {
  701.  
  702.          --column;
  703.          --buffer;
  704.     }
  705.     
  706.     // determine length
  707.  
  708.     while (((column + wordLen) < spellConfig->Len) && !IsASpace(buffer[wordLen], FALSE))
  709.         ++wordLen;
  710.  
  711.     if (replacement = CheckThisWord(apiMsg, spellConfig, buffer, wordLen, ask, volume))
  712.         if (replacement != (UBYTE *)TRUE)
  713.             Replace(apiMsg, spellConfig, column, wordLen, replacement);
  714. }
  715.  
  716. /* ------------------------------- FindNextError -------------------------------
  717.  
  718.  Jump to next error
  719.  
  720. */
  721.  
  722. LONG
  723. FindNextError(apiMsg, spellConfig)
  724.  
  725. struct APIMessage  *apiMsg;
  726. struct SpellConfig *spellConfig;
  727. {
  728.     struct EditConfig *config = apiMsg->api_Config;
  729.  
  730.     UWORD wordLen, last;
  731.     char  *buffer, *replacement;
  732.  
  733.     while (DoNextWord(apiMsg, spellConfig, FALSE)) {
  734.  
  735.         if (spellConfig->Len) {
  736.  
  737.             static struct APIModifyRequest modifyRequest = { 0 };
  738.  
  739.             // determine word length
  740.  
  741.             buffer = spellConfig->Buffer + spellConfig->Column;
  742.             last   = spellConfig->Len    - spellConfig->Column;
  743.  
  744.             wordLen = 0;
  745.  
  746.             while ((wordLen < last) && !IsASpace(buffer[wordLen], FALSE))
  747.                 ++wordLen;
  748.  
  749.             if (wordLen) {
  750.  
  751.                 // set editor's cursor position
  752.  
  753.                 modifyRequest.mr_Line   = spellConfig->Line;
  754.                 modifyRequest.mr_Column = spellConfig->Column;
  755.  
  756.                 apiMsg->api_Modify = &modifyRequest;
  757.  
  758.                 // check word, get replacement (if any)
  759.  
  760.                 if (replacement = CheckThisWord(apiMsg, spellConfig, buffer, wordLen, FALSE, spellConfig->Volume)) {
  761.  
  762.                     if (replacement != (char *)TRUE)
  763.                         Replace(apiMsg, spellConfig, spellConfig->Column, wordLen, replacement);
  764.  
  765.                     return(RC_OK);
  766.                 }
  767.             }
  768.         }
  769.     }
  770.  
  771.     ((struct APIRexxNotify *)apiMsg->api_Data)->arn_CommandError = spellConfig->AppStrings[NOMOREERRORS];
  772.  
  773.     return(RC_WARN);
  774. }
  775.  
  776. /* ------------------------------- CheckThisWord -------------------------------
  777.  
  778.  Check word <check> of length <len>. Return NULL if ok, otherwise replacement
  779.  or TRUE. Ignore single characters.
  780.  
  781. */
  782.  
  783. char *
  784. CheckThisWord(apiMsg, spellConfig, check, len, ask, volume)
  785.  
  786. struct APIMessage  *apiMsg;
  787. struct SpellConfig *spellConfig;
  788. char  *check;
  789. UWORD  len, volume;
  790. BOOL   ask;
  791. {
  792.     static char word[4096], result[4096];
  793.  
  794.     UBYTE *replacement = NULL;
  795.  
  796.     if ((len > 1) && ((spellConfig->TeX == FALSE) || (*check != 92))) {
  797.  
  798.         movmem(check, word, len);
  799.  
  800.         word[len] = 0;
  801.  
  802.         strins(word, "QUICKCHECK ");
  803.  
  804.         // make ISpell check word
  805.  
  806.         if (SendRexxCommand("IRexxSpell", word, spellConfig->RexxPort, result)) {
  807.  
  808.             if (stricmp(result, "ok")) {
  809.  
  810.                 replacement = (char *)TRUE;
  811.  
  812.                 Beep(volume);
  813.  
  814.                 // send additional CHECK command to get further information
  815.  
  816.                 if (ask && SendRexxCommand("IRexxSpell", word + 5, spellConfig->RexxPort, result)) {
  817.  
  818.                     if (*result == '&') {
  819.  
  820.                         // translate ISpell result string into exec list
  821.  
  822.                         struct List  list;
  823.                         struct Node *node, *nextNode;
  824.                         UBYTE       *start, *end, *selection;
  825.  
  826.                         // example ISpell result: "& hellu 2: hello hell"
  827.  
  828.                         if (end = strchr(result, ':')) {
  829.  
  830.                            NewList(&list);
  831.  
  832.                            while (*end) {
  833.  
  834.                                 do {
  835.  
  836.                                     *end++ = 0;
  837.  
  838.                                 } while (*end && ((*end == ',') || (*end == ' ')));
  839.  
  840.                                 start = end;
  841.  
  842.                                 while (*end && (*end != 32) && (*end != ','))
  843.                                     ++end;
  844.  
  845.                                 if (node = (struct Node *)AllocVec(sizeof(struct Node), MEMF_ANY | MEMF_CLEAR)) {
  846.  
  847.                                     // we point directly into the result string
  848.  
  849.                                     node->ln_Name = start;
  850.  
  851.                                     AddTail(&list, node);
  852.                                 }
  853.                             }
  854.  
  855.                             if (selection = ShowSpell(apiMsg->api_Global->F_ScrnName, &list, word + 11))
  856.                                 replacement = strcpy(result, selection);
  857.  
  858.                             for (node = list.lh_Head; nextNode = node->ln_Succ; node = nextNode)
  859.                                 FreeVec(node);
  860.                         }
  861.                     }
  862.                 }
  863.             }
  864.         }
  865.     }
  866.  
  867.     return(replacement);
  868. }
  869.  
  870. /* -------------------------------- AddCurrentWord -----------------------------
  871.  
  872.  Add current word to dictionary
  873.  
  874. */
  875.  
  876. LONG
  877. AddCurrentWord(apiMsg, spellConfig)
  878.  
  879. struct APIMessage  *apiMsg;
  880. struct SpellConfig *spellConfig;
  881. {
  882.     struct EditConfig *config = apiMsg->api_Config;
  883.  
  884.     UWORD column, wordLen;
  885.     UBYTE *buffer;
  886.  
  887.     column = spellConfig->Column;
  888.     buffer = spellConfig->Buffer + column;
  889.  
  890.     wordLen = 0;
  891.  
  892.     // find beginning of word
  893.  
  894.     while (column && !IsASpace(*(buffer - 1), FALSE)) {
  895.  
  896.          --column;
  897.          --buffer;
  898.     }
  899.     
  900.     // determine length
  901.  
  902.     while (((column + wordLen) < spellConfig->Len) && !IsASpace(buffer[wordLen], FALSE))
  903.         ++wordLen;
  904.  
  905.     if (wordLen) {
  906.  
  907.         static char command[1000];
  908.  
  909.         movmem(buffer, command, wordLen);
  910.  
  911.         command[wordLen] = 0;
  912.  
  913.         strins(command, "QUICKADD ");
  914.  
  915.         SendRexxCommand("IRexxSpell", command, spellConfig->RexxPort, NULL);
  916.  
  917.         ++spellConfig->Count;
  918.  
  919.         return(RC_OK);
  920.     }
  921.     else {
  922.  
  923.         ((struct APIRexxNotify *)apiMsg->api_Data)->arn_CommandError = spellConfig->AppStrings[NOWORDUNDERCURSOR];
  924.  
  925.         return(RC_WARN);
  926.     }
  927. }
  928.  
  929. ///
  930. /// "gui"
  931.  
  932. /* --------------------------------- ShowSpell ---------------------------------
  933.  
  934.  Show ISpell suggestions. Return user selection or NULL.
  935.  
  936. */
  937.  
  938. char *
  939. ShowSpell(screen, list, title)
  940.  
  941. char        *screen, *title;
  942. struct List *list;
  943. {
  944.     char *result = NULL;
  945.  
  946.     struct Screen *scr;
  947.  
  948.     if (scr = LockPubScreen(screen)) {
  949.  
  950.         struct TextFont *font;
  951.  
  952.         if (font = OpenDiskFont(scr->Font)) {
  953.  
  954.             APTR visualInfo;
  955.  
  956.             if (visualInfo = GetVisualInfoA(scr, NULL )) {
  957.  
  958.                 struct Gadget *context, *glist, *gad;
  959.  
  960.                 if (context = CreateContext(&glist)) {
  961.  
  962.                     UWORD  ww, wh, offX, offY;
  963.                     LONG   displayWidth, displayHeight;
  964.  
  965.                     struct Window *win;
  966.  
  967.                     offX  = scr->WBorLeft;
  968.                     offY  = scr->RastPort.TxHeight + scr->WBorTop + 1;
  969.  
  970.                     struct NewGadget newGad = {
  971.                     
  972.                         offX,
  973.                         offY,
  974.                         ComputeX(font, 221),
  975.                         ComputeY(font, 156),
  976.                         NULL, scr->Font, 0, 0, visualInfo, 0
  977.                     };
  978.  
  979.                     gad = CreateGadget(LISTVIEW_KIND, context, &newGad, GTLV_ShowSelected, NULL, GTLV_Labels, list, GTLV_Selected, 0, TAG_DONE);
  980.  
  981.                     rtGetVScreenSize(scr, &displayWidth, &displayHeight);
  982.  
  983.                     ww = ComputeX(font, 221);
  984.                     wh = ComputeY(font, 156);
  985.  
  986.                     if (win = OpenWindowTags( NULL,
  987.  
  988.                         WA_Left,      ((displayWidth  - ww)>>1) - scr->ViewPort.DxOffset,
  989.                         WA_Top,       ((displayHeight - wh)>>1) - scr->ViewPort.DyOffset,
  990.                         WA_Width,     ww + offX + scr->WBorRight,
  991.                         WA_Height,    wh + offY + scr->WBorBottom,
  992.                         WA_IDCMP,     LISTVIEWIDCMP | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY  | IDCMP_RAWKEY,
  993.                         WA_Flags,     WFLG_DRAGBAR  | WFLG_DEPTHGADGET  | WFLG_CLOSEGADGET  | WFLG_SMART_REFRESH | WFLG_ACTIVATE,
  994.                         WA_Gadgets,   glist,
  995.                         WA_Title,     title,
  996.                         WA_PubScreen, scr,
  997.                         TAG_DONE 
  998.  
  999.                      )) {
  1000.  
  1001.                         ULONG class;
  1002.                         UWORD active;
  1003.  
  1004.                         active = 0;
  1005.                         result = list->lh_Head->ln_Name;
  1006.  
  1007.                         struct IntuiMessage *msg;
  1008.                         struct Node         *node;
  1009.  
  1010.                         GT_RefreshWindow(win, NULL);
  1011.  
  1012.                         do {
  1013.  
  1014.                             while (!(msg = GT_GetIMsg(win->UserPort)))
  1015.                                 WaitPort(win->UserPort);
  1016.  
  1017.                             switch (class = msg->Class) {
  1018.  
  1019.                                 case RAWKEY:
  1020.  
  1021.                                     WORD step = (msg->Code == CURSORUP) ? -1 : 1;
  1022.  
  1023.                                     if (node = SearchNode(list, active + step)) {
  1024.  
  1025.                                         active += step;
  1026.                                         result  = node->ln_Name;
  1027.  
  1028.                                         GT_SetGadgetAttrs(gad, win, NULL, GTLV_Selected, active, GTLV_MakeVisible, active, TAG_DONE);
  1029.                                     }
  1030.  
  1031.                                     break;
  1032.  
  1033.                                 case IDCMP_VANILLAKEY:
  1034.  
  1035.                                     if (msg->Code == 27)
  1036.                                         class  = CLOSEWINDOW;
  1037.  
  1038.                                     if (msg->Code == 13)
  1039.                                         class = IDCMP_GADGETUP;
  1040.  
  1041.                                     break;
  1042.  
  1043.                                 case IDCMP_GADGETUP:
  1044.  
  1045.                                     result = SearchNode(list, active = msg->Code)->ln_Name;
  1046.                                     break;
  1047.                             }
  1048.  
  1049.                             GT_ReplyIMsg(msg);
  1050.  
  1051.                         } while ((class & (GADGETUP | CLOSEWINDOW)) == NULL);
  1052.  
  1053.                         if (class == CLOSEWINDOW)
  1054.                             result = NULL;
  1055.  
  1056.                         CloseWindow(win);
  1057.                     }
  1058.                 }
  1059.                 FreeVisualInfo(visualInfo);
  1060.             }
  1061.         }
  1062.         UnlockPubScreen(screen, scr);
  1063.     }
  1064.  
  1065.     return(result);
  1066. }
  1067.  
  1068. /* --------------------------------- ComputeX ----------------------------------
  1069.  
  1070.  Resize element of width <value> according to current font
  1071.  
  1072. */
  1073.  
  1074. UWORD 
  1075. ComputeX(font, value)
  1076.  
  1077. UWORD  value;
  1078. struct TextFont *font;
  1079. {
  1080.     return((font->tf_XSize * value) / 8);
  1081. }          
  1082.  
  1083. /* --------------------------------- ComputeY ----------------------------------
  1084.  
  1085.  Resize element of height <value> according to current font
  1086.  
  1087. */
  1088.  
  1089. UWORD 
  1090. ComputeY(font, value)
  1091.  
  1092. UWORD  value;
  1093. struct TextFont *font;
  1094. {
  1095.     return((font->tf_YSize * value) / 8);
  1096. }
  1097.  
  1098. ///
  1099. /// "ed"
  1100.  
  1101. /* ----------------------------------- Replace ---------------------------------
  1102.  
  1103.  Replace word of length <wordLen> at position <pos> within current line by 
  1104.  string <replacement>
  1105.  
  1106. */
  1107.  
  1108. void
  1109. Replace(apiMsg, spellConfig, column, wordLen, replacement)
  1110.  
  1111. struct APIMessage  *apiMsg;
  1112. struct SpellConfig *spellConfig;
  1113. char               *replacement;
  1114. UWORD               column, wordLen;
  1115. {
  1116.     static struct APIModifyRequest modifyRequest;
  1117.     static UBYTE                   buffer[4096];
  1118.  
  1119.     struct EditConfig *config = apiMsg->api_Config;
  1120.  
  1121.     UWORD  newLen;
  1122.     UBYTE *next;
  1123.  
  1124.     // copy current line
  1125.  
  1126.     movmem(spellConfig->Buffer, buffer, spellConfig->Len);
  1127.  
  1128.     newLen = strlen(replacement);
  1129.     next   = buffer + column;
  1130.  
  1131.     // replace old word by selection from dictionary
  1132.  
  1133.     if (newLen != wordLen)
  1134.         movmem(next + wordLen, next + newLen, spellConfig->Len - column - wordLen);
  1135.  
  1136.     movmem(replacement, next, newLen);
  1137.  
  1138.     // make GoldED change line
  1139.  
  1140.     modifyRequest.mr_Next   = NULL;
  1141.     modifyRequest.mr_Line   = spellConfig->Line;
  1142.     modifyRequest.mr_Column = spellConfig->Column;
  1143.     modifyRequest.mr_Size   = spellConfig->Len + (newLen - wordLen);
  1144.     modifyRequest.mr_Data   = buffer;
  1145.  
  1146.     if (column <= spellConfig->Column)
  1147.         modifyRequest.mr_Column += (newLen - wordLen);
  1148.  
  1149.     apiMsg->api_Modify = &modifyRequest;
  1150. }
  1151.  
  1152. /* ---------------------------------- DoNextWord -------------------------------
  1153.  
  1154.  Move cursor to beginning of next word. If <strict> is TRUE, only 32(dez) is
  1155.  considered as 'space character', otherwise all non-alphanumerical characters
  1156.  (e.g. ',') are considered as 'space', too. Return FALSE on failure (end of
  1157.  text)
  1158.  
  1159. */
  1160.  
  1161. BOOL
  1162. DoNextWord(apiMsg, spellConfig, strict)
  1163.  
  1164. struct APIMessage  *apiMsg;
  1165. struct SpellConfig *spellConfig;
  1166. BOOL   strict;
  1167. {
  1168.     struct EditConfig *config = apiMsg->api_Config;
  1169.  
  1170.     if (spellConfig->Line >= config->Lines)
  1171.  
  1172.         return(FALSE);
  1173.  
  1174.     else {
  1175.  
  1176.         // look for end of current word
  1177.  
  1178.         if ((spellConfig->Column + 1) >= spellConfig->Len) {
  1179.  
  1180.             if ((spellConfig->Line + 1) >= config->Lines)
  1181.                 return(FALSE);
  1182.             else
  1183.                 DoRightSmart(apiMsg, spellConfig);
  1184.         }
  1185.         else {
  1186.  
  1187.             while (!IsASpace((spellConfig->Buffer)[spellConfig->Column], strict)) {
  1188.  
  1189.                 if (DoRightSmart(apiMsg, spellConfig)) {
  1190.  
  1191.                     if (spellConfig->Line >= config->Lines)
  1192.                         return(FALSE);
  1193.  
  1194.                     break;
  1195.                 }
  1196.             }
  1197.         }
  1198.  
  1199.         // look for beginning of next word
  1200.  
  1201.         if (spellConfig->Len) {
  1202.  
  1203.             while (IsASpace((spellConfig->Buffer)[spellConfig->Column], strict)) {
  1204.  
  1205.                 if (DoRightSmart(apiMsg, spellConfig)) {
  1206.  
  1207.                     if (spellConfig->Line >= config->Lines)
  1208.                         return(FALSE);
  1209.                     else
  1210.                         break;
  1211.                 }
  1212.             }
  1213.         }
  1214.  
  1215.         return(TRUE);
  1216.     }
  1217. }
  1218.  
  1219. /* --------------------------------- IsASpace ----------------------------------
  1220.  
  1221.  Return TRUE if character is considered to be a 'white space'. Only SPC is 
  1222.  considered to be white space if <strict> is TRUE.
  1223.  
  1224. */
  1225.  
  1226. BOOL
  1227. IsASpace(code, strict)
  1228.  
  1229. UBYTE code;
  1230. BOOL  strict;
  1231. {
  1232.     if (strict)
  1233.         return(code == 32);
  1234.     else
  1235.         return ((code < 'A') || ((code >= 128) && (code <= 160)) || strchr(".,;:!()[]{}-/»«", code));
  1236. }
  1237.  
  1238. /* ------------------------------- DoRightSmart --------------------------------
  1239.  
  1240.  Move cursor right to non-space column if there are characters left, else jump to
  1241.  beginning of next line. Return TRUE if passing end of line.
  1242.  
  1243. */
  1244.  
  1245. BOOL
  1246. DoRightSmart(apiMsg, spellConfig)
  1247.  
  1248. struct APIMessage  *apiMsg;
  1249. struct SpellConfig *spellConfig;
  1250. {
  1251.     struct EditConfig *config = apiMsg->api_Config;
  1252.  
  1253.     UBYTE *next, *last;
  1254.  
  1255.     next = spellConfig->Buffer + spellConfig->Column;
  1256.     last = spellConfig->Buffer + spellConfig->Len;
  1257.  
  1258.     while (++next < last) {
  1259.  
  1260.         if (*next != 32) {
  1261.  
  1262.             DoRight(apiMsg, spellConfig);
  1263.  
  1264.             return(FALSE);
  1265.         }
  1266.     }
  1267.  
  1268.     if ((spellConfig->Line + 1) < config->Lines) {
  1269.  
  1270.         spellConfig->Column = 0;
  1271.  
  1272.         DoDown(apiMsg, spellConfig);
  1273.     }
  1274.  
  1275.     return(TRUE);
  1276. }
  1277.  
  1278. /* ---------------------------------- DoRight ----------------------------------
  1279.  
  1280.  Move cursor one column right
  1281.  
  1282. */
  1283.  
  1284. void
  1285. DoRight(apiMsg, spellConfig)
  1286.  
  1287. struct APIMessage  *apiMsg;
  1288. struct SpellConfig *spellConfig;
  1289. {
  1290.     if (spellConfig->Column != (EDIT_MAXWIDTH - 1))
  1291.         ++spellConfig->Column;
  1292. }
  1293.  
  1294.  
  1295. /* ---------------------------------- DoDown -------------------------------------
  1296.  
  1297.  Move cursor down (but don't exeed last line of text).
  1298.  
  1299. */
  1300.  
  1301. void
  1302. DoDown(apiMsg, spellConfig)
  1303.  
  1304. struct APIMessage  *apiMsg;
  1305. struct SpellConfig *spellConfig;
  1306. {
  1307.     struct EditConfig *config = apiMsg->api_Config;
  1308.  
  1309.     if (++spellConfig->Line < config->Lines) {
  1310.  
  1311.         struct LineNode *node = config->TextNodes + spellConfig->Line;
  1312.  
  1313.         spellConfig->Buffer = node->Text;
  1314.         spellConfig->Len    = node->Len;
  1315.     }
  1316. }
  1317.  
  1318. ///
  1319. /// "misc"
  1320.  
  1321. /* ---------------------------------- Exists -----------------------------------
  1322.  
  1323.  Check if file exists
  1324.  
  1325. */
  1326.  
  1327. BOOL
  1328. Exists(file)
  1329.  
  1330. UBYTE *file;
  1331. {
  1332.     BPTR lock;
  1333.  
  1334.     if (lock = Lock(file, ACCESS_READ)) {
  1335.  
  1336.         UnLock(lock);
  1337.  
  1338.         return(TRUE);
  1339.     }
  1340.     else
  1341.         return(FALSE);
  1342. }
  1343.  
  1344.  
  1345. /* ----------------------------------- Information -----------------------------
  1346.  
  1347.  Show info requester
  1348.  
  1349. */
  1350.  
  1351. UWORD
  1352. Information(apiMsg, body, button)
  1353.  
  1354. struct APIMessage *apiMsg;
  1355. char  *body, *button;
  1356. {
  1357.     return(rtEZRequestTags(body, button ? button : "_OK", NULL, NULL,
  1358.  
  1359.         RT_Underscore,    '_',
  1360.         RTEZ_ReqTitle,    "SpellIT",
  1361.         RT_PubScrName,    apiMsg ? apiMsg->api_Global->F_ScrnName : NULL,
  1362.         TAG_DONE)
  1363.     );
  1364. }
  1365.  
  1366. /* --------------------------------- AlertInfo -----------------------------------
  1367.  
  1368.  Show alert. Returns TRUE if user pressed left button.
  1369.  
  1370. */
  1371.  
  1372. BOOL
  1373. AlertInfo(text)
  1374.  
  1375. char *text;
  1376. {
  1377.     BOOL result = FALSE;
  1378.  
  1379.     if (text) {
  1380.  
  1381.         char *buffer;
  1382.  
  1383.         if (buffer = AllocVec(80, MEMF_PUBLIC | MEMF_CLEAR)) {
  1384.  
  1385.             buffer[1] = '\30';
  1386.             buffer[2] = '\25';
  1387.  
  1388.             strcpy(buffer + 3, text);
  1389.  
  1390.             result = DisplayAlert(RECOVERY_ALERT, buffer, 40);
  1391.  
  1392.             FreeVec(buffer);
  1393.         }
  1394.     }
  1395.  
  1396.     return(result);
  1397. }
  1398.  
  1399.  
  1400. /* ---------------------------------- EvaluateBool -----------------------------
  1401.  
  1402.  Read slot <slot> of command array filled out by dos/ReadArgs(). Return code
  1403.  depends on slot value: return TRUE if CommandArgs[<slot>] is pointing to string
  1404.  "TRUE". Return !<oldValue> if it is pointing to "TOGGLE" (old value has to bee
  1405.  valid). Return FALSE in any other case. This function does write to <oldValue>
  1406.  (if valid).
  1407.  
  1408. */
  1409.  
  1410. BOOL
  1411. EvaluateBool(oldValue, slot, argArray)
  1412.  
  1413. BOOL  *oldValue;
  1414. ULONG *argArray;
  1415. UWORD slot;
  1416. {
  1417.     BOOL result = oldValue ? *oldValue : FALSE;
  1418.  
  1419.     if (argArray[slot]) {
  1420.  
  1421.         result = stricmp((char *)argArray[slot], "TOGGLE") ? !stricmp((char *)argArray[slot], "TRUE") : !result;
  1422.  
  1423.         if (oldValue)
  1424.             *oldValue = result;
  1425.     }
  1426.     return(result);
  1427. }
  1428.  
  1429.  
  1430. /* ---------------------------------- SearchNode --------------------------------
  1431.  
  1432.  Return pointer to node if ordinal number (0, ...) is known.
  1433.  
  1434. */
  1435.  
  1436. struct Node *
  1437. SearchNode(list, ordinal)
  1438.  
  1439. struct List *list;
  1440. UWORD  ordinal;
  1441. {
  1442.     struct Node *node;
  1443.  
  1444.     for (node = list->lh_Head; node->ln_Succ; --ordinal, node = node->ln_Succ)
  1445.         if (!ordinal)
  1446.             return(node);
  1447.  
  1448.     return(NULL);
  1449. }
  1450.  
  1451. /* ----------------------------------- Beep ------------------------------------
  1452.  
  1453.  Short audible beep
  1454.  
  1455. */
  1456.  
  1457. void
  1458. Beep(volume)
  1459.  
  1460. UWORD volume;
  1461. {
  1462.     if (volume) {
  1463.         struct IOAudio *audioIO;
  1464.  
  1465.         if (audioIO = (struct IOAudio *)AllocVec(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR)) {
  1466.  
  1467.             struct MsgPort *audioMP;
  1468.  
  1469.             if (audioMP = CreateMsgPort()) {
  1470.  
  1471.                 UBYTE whichannel[] = { 1, 2, 4, 8 };
  1472.  
  1473.                 audioIO->ioa_Request.io_Message.mn_ReplyPort   = audioMP;
  1474.                 audioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  1475.                 audioIO->ioa_Request.io_Command                = ADCMD_ALLOCATE;
  1476.                 audioIO->ioa_Request.io_Flags                  = ADIOF_NOWAIT;
  1477.                 audioIO->ioa_AllocKey                          = 0;
  1478.                 audioIO->ioa_Data                              = whichannel;
  1479.                 audioIO->ioa_Length                            = sizeof(whichannel);
  1480.  
  1481.                 if (!OpenDevice("audio.device", 0, (struct IORequest *)audioIO, 0)) {
  1482.  
  1483.                     __chip const static UBYTE waveptr[2] = {127, -127};
  1484.  
  1485.                     audioIO->ioa_Request.io_Message.mn_ReplyPort = audioMP;
  1486.                     audioIO->ioa_Request.io_Command              = CMD_WRITE;
  1487.                     audioIO->ioa_Request.io_Flags                = ADIOF_PERVOL;
  1488.  
  1489.                     audioIO->ioa_Data   = waveptr;
  1490.                     audioIO->ioa_Length = 2;
  1491.                     audioIO->ioa_Period = 1015;
  1492.                     audioIO->ioa_Volume = volume;
  1493.                     audioIO->ioa_Cycles = 60; // 44;
  1494.  
  1495.                     BeginIO((struct IORequest *)audioIO );
  1496.  
  1497.                     WaitPort(audioMP);
  1498.                     GetMsg  (audioMP);
  1499.  
  1500.                     CloseDevice((struct IORequest *)audioIO);
  1501.                 }
  1502.                 DeleteMsgPort(audioMP);
  1503.             }
  1504.             FreeVec(audioIO);
  1505.         }
  1506.     }
  1507.     else
  1508.         DisplayBeep(0);
  1509. }
  1510.  
  1511.  
  1512. ///
  1513. /// "arexx"
  1514.  
  1515. /* ---------------------------------- SendRexxCommand -------------------------
  1516.  
  1517.  Send ARexx message & wait for answer. Return pointer to result or NULL.
  1518.  
  1519. */
  1520.  
  1521. ULONG *
  1522. SendRexxCommand(port, cmd, replyPort, buffer)
  1523.  
  1524. char   *cmd, *port, *buffer;
  1525. struct MsgPort *replyPort;
  1526. {
  1527.     struct MsgPort *rexxport;
  1528.  
  1529.     Forbid();
  1530.  
  1531.     if (rexxport = FindPort(port)) {
  1532.  
  1533.         struct RexxMsg *rexxMsg, *answer;
  1534.  
  1535.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  1536.  
  1537.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  1538.  
  1539.                 static ULONG result;
  1540.  
  1541.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  1542.  
  1543.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  1544.  
  1545.                 do {
  1546.                     
  1547.                     WaitPort(replyPort);
  1548.  
  1549.                     if (answer = (struct RexxMsg *)GetMsg(replyPort))
  1550.                         result = answer->rm_Result1;
  1551.  
  1552.                 } while (!answer);
  1553.  
  1554.                 Permit();
  1555.  
  1556.                 if (answer->rm_Result1 == RC_OK) {
  1557.  
  1558.                     if (answer->rm_Result2) {
  1559.  
  1560.                         if (buffer)
  1561.                             strcpy(buffer, (char *)answer->rm_Result2);
  1562.  
  1563.                         DeleteArgstring((char *)answer->rm_Result2);
  1564.                     }
  1565.                 }
  1566.  
  1567.                 DeleteArgstring((char *)ARG0(answer));
  1568.  
  1569.                 DeleteRexxMsg(answer);
  1570.  
  1571.                 return(&result);
  1572.             }
  1573.         }
  1574.     }
  1575.  
  1576.     Permit();
  1577.  
  1578.     return(NULL);
  1579. }
  1580.  
  1581. ///
  1582.